package org.jetbrains.idea.accurev.application;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.VcsConfiguration;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.VcsVFSListener;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileEvent;
import org.jetbrains.idea.accurev.AccuRevBundle;
import org.jetbrains.idea.accurev.operations.P4AddOperation;
import org.jetbrains.idea.accurev.operations.P4CopyOperation;
import org.jetbrains.idea.accurev.operations.P4MoveRenameOperation;
import org.jetbrains.idea.accurev.accurev.FStat;
import org.jetbrains.idea.accurev.accurev.P4File;
import org.jetbrains.idea.accurev.accurev.AccuRevSettings;

import java.util.Collection;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;

/**
 * @author yole
 */
public class PerforceVFSListener extends VcsVFSListener {
  public PerforceVFSListener(final Project project) {
    super(project, AccuRevVcs.getInstance(project));
  }

  @Override
  protected boolean isEventIgnored(final VirtualFileEvent event) {
    return super.isEventIgnored(event) || event.getRequestor() instanceof PerforceOfflineRollbackEnvironment;
  }

  protected void performAdding(final Collection<VirtualFile> addedFiles, final Map<VirtualFile, VirtualFile> copyFromMap) {
    VcsBackgroundTask<VirtualFile> task = new VcsBackgroundTask<VirtualFile>(myProject,
                                                                             AccuRevBundle.message("progress.title.running.perforce.commands"),
                                                                             VcsConfiguration.getInstance(myProject).getAddRemoveOption(),
                                                                             addedFiles) {
      protected void process(final VirtualFile item) throws VcsException {
        createdVFile(item, copyFromMap);
      }
    };

    AccuRevVcs.getInstance(myProject).runTask(task);
  }

  private void createdVFile(final VirtualFile vFile, final Map<VirtualFile, VirtualFile> copyFromMap) throws VcsException {
    if (vFile.isDirectory()) {
      return;
    }

    VirtualFile copyFrom = copyFromMap.get(vFile);
    final String changeList = ChangeListManager.getInstance(myProject).getDefaultChangeList().getName();
    if (copyFrom != null && !isAdding(copyFrom)) {
      new P4CopyOperation(changeList, vFile, copyFrom).executeOrLog(myProject);
    }
    else {
      new P4AddOperation(changeList, vFile).executeOrLog(myProject);
    }
  }

  private boolean isAdding(final VirtualFile copyFrom) throws VcsException {
    if (!AccuRevSettings.getSettings(myProject).ENABLED) {
      return false;
    }
    final FStat sourceFStat = P4File.create(copyFrom).getFstat(myProject, true);
    return sourceFStat.local == FStat.LOCAL_ADDING;
  }

  protected String getSingleFileAddPromptTemplate() {
    return AccuRevBundle.message("confirmation.text.add.files");
  }

  protected String getSingleFileAddTitle() {
    return AccuRevBundle.message("confirmation.title.add.files");
  }

  protected String getAddTitle() {
    return AccuRevBundle.message("add.select.files");
  }

  @Override
  protected VcsDeleteType needConfirmDeletion(final VirtualFile file) {
    final P4File p4File = P4File.create(file);

    if (AccuRevSettings.getSettings(myProject).ENABLED) {
      try {
        final FStat fstat = p4File.getFstat(myProject, true);

        if (fstat.status == FStat.STATUS_NOT_ADDED ||
            fstat.status == FStat.STATUS_NOT_IN_CLIENTSPEC ||
            fstat.status == FStat.STATUS_UNKNOWN ||
            fstat.local == FStat.LOCAL_NOT_LOCAL) {
          return VcsDeleteType.IGNORE;
        }

        if (fstat.status == FStat.STATUS_ONLY_LOCAL) {
          return VcsDeleteType.SILENT;
        }
      }
      catch (VcsException e) {
        //ignore
      }
    }
    return VcsDeleteType.CONFIRM;
  }

  protected void performDeletion(final List<FilePath> filesToDelete) {
    AccuRevVcs.getInstance(myProject).getOfflineCheckinEnvironment().scheduleMissingFileForDeletion(filesToDelete);
  }

  protected String getSingleFileDeletePromptTemplate() {
    return AccuRevBundle.message("confirmation.text.remove.files");
  }

  protected String getSingleFileDeleteTitle() {
    return AccuRevBundle.message("confirmation.title.remove.files");
  }

  protected String getDeleteTitle() {
    return AccuRevBundle.message("delete.select.files");
  }

  protected void processMovedFile(final VirtualFile file, final String newParentPath, final String newName) {
    P4File.invalidateFstat(file);
    super.processMovedFile(file, newParentPath, newName);
  }

  protected void performMoveRename(final List<MovedFileInfo> movedFiles) {
    VcsBackgroundTask<MovedFileInfo> task = new VcsBackgroundTask<MovedFileInfo>(myProject,
                                                                                 AccuRevBundle.message("progress.title.running.perforce.commands"),
                                                                                 VcsConfiguration.getInstance(myProject).getAddRemoveOption(),
                                                                                 new ArrayList<MovedFileInfo>(movedFiles)) {
      protected void process(final MovedFileInfo info) throws VcsException {
        new P4MoveRenameOperation(ChangeListManager.getInstance(myProject).getDefaultChangeList().getName(),
                                  info.myOldPath, info.myNewPath).executeOrLog(myProject);
      }
    };

    AccuRevVcs.getInstance(myProject).runTask(task);
  }

  protected boolean isDirectoryVersioningSupported() {
    return false;
  }
}
